#include<stdlib.h>
#include<stdio.h>

#include "elf.h"

int a = 3;

int main(int argc, char *argv[])
{
	// 参数错误
	if (argc < 2) {
		printf("invalid arguments\n");
		exit(0);
	}
	// 打开文件
	FILE *fp;
	fp = fopen(argv[1], "r");
	if (NULL == fp) {
		printf("fail to open the file");
		exit(0);
	}
	// 解析head
	struct Elf64_Ehdr elf_head;
	int shnum, a;

	// 读取 head 到elf_head
	a = fread(&elf_head, sizeof(struct Elf64_Ehdr), 1, fp);
	if (0 == a) {
		printf("fail to read head\n");
		exit(0);
	}
	// 判断elf文件类型
	if (elf_head.e_ident[0] != 0x7F ||
	    elf_head.e_ident[1] != 'E' ||
	    elf_head.e_ident[2] != 'L' || elf_head.e_ident[3] != 'F') {
		printf("Not a ELF file\n");
		exit(0);
	}
	// 解析section 分配内存 section * 数量
	struct Elf64_Shdr *shdr =
	    (struct Elf64_Shdr *)malloc(sizeof(struct Elf64_Shdr) *
					elf_head.e_shnum);
	if (NULL == shdr) {
		printf("shdr malloc failed\n");
		exit(0);
	}
	// 设置fp偏移量 offset
	a = fseek(fp, elf_head.e_shoff, SEEK_SET);
	if (0 != a) {
		printf("\nfaile to fseek\n");
		exit(0);
	}
	// 读取section 到 shdr, 大小为shdr * 数量
	a = fread(shdr, sizeof(struct Elf64_Shdr) * elf_head.e_shnum, 1, fp);
	if (0 == a) {
		printf("\nfail to read section\n");
		exit(0);
	}
	// 重置指针位置
	rewind(fp);

#if 0

#endif

	// 将fp指针移到 字符串表偏移位置处
	fseek(fp, shdr[elf_head.e_shstrndx].sh_offset, SEEK_SET);

	// 第e_shstrndx项是字符串表 定义 字节 长度 char类型 数组
	char shstrtab[shdr[elf_head.e_shstrndx].sh_size];
	char *temp = shstrtab;

	// 读取内容
	a = fread(shstrtab, shdr[elf_head.e_shstrndx].sh_size, 1, fp);
	if (0 == a) {
		printf("\nfaile to read\n");
	}
	// printf("\n\节的信息： \n");
	// 遍历
	// for (int i = 0; i < elf_head.e_shnum; i++)
	// {
	// temp = shstrtab;
	// temp = temp + shdr[i].sh_name;
	// printf("节的名称: %s\n", temp);
	// printf("节首的偏移: %x\n", shdr[i].sh_offset);
	// printf("节的大小: %x\n", shdr[i].sh_size);
	// printf("节尾的地址: %x\n", shdr[i].sh_offset + shdr[i].sh_size);
	// printf("\n");
	// }

	// 解析 segment
	struct Elf64_Phdr *phdr =
	    (struct Elf64_Phdr *)malloc(sizeof(struct Elf64_Phdr) *
					elf_head.e_phnum);
	a = fseek(fp, elf_head.e_phoff, SEEK_SET);
	a = fread(phdr, sizeof(struct Elf64_Phdr) * elf_head.e_phnum, 1, fp);
	rewind(fp);
	fseek(fp, phdr[elf_head.e_shentsize].p_offset, SEEK_SET);
	char phstrtab[phdr[elf_head.e_shentsize].p_filesz];
	a = fread(phstrtab, phdr[elf_head.e_shentsize].p_filesz, 1, fp);
	printf("\n\n段的信息：\n");

	for (int i = 0; i < elf_head.e_phnum; i++) {
		printf("%d: \n", i);
		printf(" 该段首相对偏移: %llx \n", phdr[i].p_offset);
		printf(" 该段的大小: %llx \n", phdr[i].p_memsz);
		printf(" 该段尾相对偏移: %llx \n",
		       phdr[i].p_memsz + phdr[i].p_offset);
		printf(" *该段包含的节有：\n");

		for (int j = 0; j < elf_head.e_shnum; j++) {
			if ((shdr[j].sh_offset > phdr[i].p_offset) &&
			    ((shdr[j].sh_offset + shdr[j].sh_size) <
			     (phdr[i].p_offset + phdr[i].p_memsz))
			    ) {
				temp = shstrtab;
				temp = temp + shdr[j].sh_name;

				printf(" 节的名称: %s\n", temp);
				printf(" 节首的偏移: %llx\n",
				       shdr[j].sh_offset);
				printf(" 节的大小: %llx\n",
				       shdr[j].sh_size);
				printf(" 节尾的地址: %llx\n",
				       shdr[j].sh_offset + shdr[j].sh_size);
				printf("\n");
			}
		}
		printf("\n");
	}

//test sh_info
	int err;
	for (int i = 0; i < elf_head.e_shnum; i++) {
		unsigned int infosec = shdr[i].sh_info;
		printf("infosec: %d\n", infosec);
        /* Not a valid relocation section? */
        if (infosec >= elf_head.e_shnum)
                continue;
        // /* Don't bother with non-allocated sections */
        // if (!(shdr[infosec].sh_flags & SHF_ALLOC))
        //         continue;
        // 是重定位段
        // if (shdr[i].sh_type == SHT_REL)
        //         err = apply_relocate(info->sechdrs, info->strtab,
        //                 info->index.sym, i, mod);
        // else if (info->sechdrs[i].sh_type == SHT_RELA)
        //         err = apply_relocate_add(info->sechdrs, info->strtab,
        //                                  info->index.sym, i, mod);
        // if (err < 0)
        //         break;

	}

	printf("\n");
	return 0;
}

#if 0

static void get_rel_dyn_type(u2 machineType,u4 rInfo,u1* type);
 
void print_elf_section_of_reldyn(MemMapping* mem,Elf32_Ehdr* pHeader,Elf32_Shdr* pSheader){
	Elf32_Rel* pRel						= NULL;
	Elf32_Sym* pSymMem  			    = NULL;
	u1* shStringTableMem				= NULL;
	u4 i 								= 0;
	u4 size								= 0;
	u1 buf[55];
	LookupSection* pLookupSection 		= NULL;
	LookupSection* pLookupStrSection 	= NULL;
	Elf32_Shdr* pReldyn					= NULL;
	shStringTableMem = get_elf_section_of_shstr_table(mem,pHeader,pSheader);
	if(NULL == shStringTableMem){
		printf("Error,get elf section header string table failed !\n");
		goto Exit;
	}
 
	for( ; i < pHeader->e_shnum ; i++){
		if(pSheader[i].sh_type == SHT_REL && strcmp((const char*)(shStringTableMem + pSheader[i].sh_name),".rel.dyn") == 0){
			size = (pSheader[i].sh_size / pSheader[i].sh_entsize);
			pRel = (Elf32_Rel*)(mem->base + pSheader[i].sh_offset);
			pReldyn = (Elf32_Shdr*) &pSheader[i];
			break;
		}
		continue;
	}
 
	if(NULL != pRel){
		//@1 by default ,rel.dyn link dynsym ,so it sh_link is the index
		pLookupSection = get_section_by_index(mem,pHeader,pSheader,pReldyn->sh_link);
		if(NULL == pLookupSection){
			printf("Error,get section by index failed\n");
			goto Exit;
		}
		pSymMem = (Elf32_Sym*)pLookupSection->base;
		pLookupStrSection = get_section_by_index(mem,pHeader,pSheader,pLookupSection->link);
		if(NULL == pLookupStrSection){
			printf("Error,get sym tab link failed\n");
			goto Exit;
		}
		i = 0;
		printf("Relocation section '.rel.dyn' at offset 0x%.8x contains %d entries:\n",pReldyn->sh_addr,size);
		printf("Offset     Info     Type           Sym.Value  Sym. Name\n");
		for( ; i < size ; i++ ){
			printf("0x%.8x ",pRel[i].r_offset);
			printf("%.8x ",pRel[i].r_info);
			memset(&buf,0,55);
			get_rel_dyn_type((u2)pHeader->e_machine,(u4)ELF32_R_TYPE(pRel[i].r_info),(u1*)buf);
			printf("%-15s",buf);
			if(pSymMem[ELF32_R_SYM(pRel[i].r_info)].st_name != 0){
				printf("%.8x   ",pSymMem[ELF32_R_SYM(pRel[i].r_info)].st_value);
				printf("%s",(pLookupStrSection->base + pSymMem[ELF32_R_SYM(pRel[i].r_info)].st_name));
			}
			printf("\n");
		}
	}
 
	Exit:
	if(shStringTableMem)
		free(shStringTableMem);
	if(pLookupSection)
		free(pLookupSection);
	if(pLookupStrSection)
		free(pLookupStrSection);
}
 
//this impl  code almost sample as the top  print_elf_section_of_reldyn，but its' sh_info  point to which section will be relocated
void print_elf_section_of_relplt(MemMapping* mem,Elf32_Ehdr* pHeader,Elf32_Shdr* pSheader){
	Elf32_Rel* pRelplt					= NULL;
	Elf32_Sym* pSymMem  			    = NULL;
	u1* shStringTableMem				= NULL;
	u4 i 								= 0;
	u4 size								= 0;
	u1 buf[55];
	LookupSection* pLookupSection 		= NULL;
	LookupSection* pLookupStrSection 	= NULL;
	Elf32_Shdr* pThisSection			= NULL;
 
	shStringTableMem = get_elf_section_of_shstr_table(mem,pHeader,pSheader);
	if(NULL == shStringTableMem){
		printf("Error,get elf section header string table failed !\n");
		goto Exit;
	}
 
	for( ; i < pHeader->e_shnum ; i++){
		if(pSheader[i].sh_type == SHT_REL && strcmp((const char*)(shStringTableMem + pSheader[i].sh_name),".rel.plt") == 0){
			size = (pSheader[i].sh_size / pSheader[i].sh_entsize);
			pRelplt =  (Elf32_Rel*)(mem->base + pSheader[i].sh_offset);
			pThisSection = (Elf32_Shdr*)&pSheader[i];
			break;
		}
		continue;
	}
 
	if(NULL != pRelplt){
		//@1 by default ,rel.dyn link dynsym ,so it sh_link is the index
		pLookupSection = get_section_by_index(mem,pHeader,pSheader,pThisSection->sh_link);
		if(NULL == pLookupSection){
			printf("Error,get section by index failed\n");
			goto Exit;
		}
 
		pSymMem = (Elf32_Sym*)pLookupSection->base;
		pLookupStrSection = get_section_by_index(mem,pHeader,pSheader,pLookupSection->link);
		if(NULL == pLookupStrSection){
			printf("Error,get sym tab link failed\n");
			goto Exit;
		}
		i = 0;
		printf("Relocation section '.rel.plt' at offset 0x%.8x contains %d entries:\n",pThisSection->sh_addr,size);
		printf("Offset     Info     Type           Sym.Value  Sym. Name\n");
		for( ; i < size ; i++ ){
			printf("0x%.8x ",pRelplt[i].r_offset);
			printf("%.8x ",pRelplt[i].r_info);
			memset(&buf,0,55);
			get_rel_dyn_type((u2)pHeader->e_machine,(u4)ELF32_R_TYPE(pRelplt[i].r_info),(u1*)buf);
			printf("%s ",buf);
			if(pSymMem[ELF32_R_SYM(pRelplt[i].r_info)].st_name != 0){
				printf("%.8x ",pSymMem[ELF32_R_SYM(pRelplt[i].r_info)].st_value);
				printf("%s",(pLookupStrSection->base + pSymMem[ELF32_R_SYM(pRelplt[i].r_info)].st_name));
			}
			printf("\n");
		}
	}
 
	Exit:
	if(shStringTableMem)
		free(shStringTableMem);
	if(pLookupSection)
		free(pLookupSection);
	if(pLookupStrSection)
		free(pLookupStrSection);
}
 
 
 
void print_elf_section_of_allrela(MemMapping* mem,Elf32_Ehdr* pHeader,Elf32_Shdr* pSheader){
	Elf32_Rela* pRelplt					= NULL;
	Elf32_Sym* pRelaMem  			    = NULL;
	u4 i 								= 0;
	u4 size								= 0;
	u1 buf[55];
	LookupSection* pLookupSection 		= NULL;
	LookupSection* pLookupStrSection 	= NULL;
	Elf32_Shdr* pThisSection;
	u1* shStringTableMem				= NULL;
 
	shStringTableMem = get_elf_section_of_shstr_table(mem,pHeader,pSheader);
	if(NULL == shStringTableMem){
		printf("Error,get elf section header string table failed !\n");
		goto Exit;
	}
 
	for( ; i < pHeader->e_shnum ; i++){
		if(pSheader[i].sh_type == SHT_RELA){
			size = (pSheader[i].sh_size / pSheader[i].sh_entsize);
			pRelplt = (Elf32_Rela*)(mem->base + pSheader[i].sh_offset);
			pThisSection = (Elf32_Shdr*)(&pSheader[i]);
			if(NULL != pRelplt){
				//@1 by default ,RELA link dynsym ,so it sh_link is the index
				pLookupSection = get_section_by_index(mem,pHeader,pSheader,pThisSection->sh_link);
				if(NULL == pLookupSection){
					printf("Error,get section by index failed\n");
					goto Exit;
				}
				pRelaMem = (Elf32_Sym*)pLookupSection->base;
 
				pLookupStrSection = get_section_by_index(mem,pHeader,pSheader,pLookupSection->link);
				if(NULL == pLookupStrSection){
					printf("Error,get sym tab link failed\n");
					goto Exit;
				}
 
				u4 j = 0;
				printf("Relocation section '%s' at offset 0x%.8x contains %d entries:\n",(shStringTableMem + pSheader[i].sh_name),pThisSection->sh_offset,size);
				printf("Offset     Info     Type           Sym.Value  Sym. Name + Addend\n");
				for( ; j < size ; j++ ){
					printf("0x%.8x ",pRelplt[j].r_offset);
					printf("%.8x ",pRelplt[j].r_info);
					memset(&buf,0,55);
					get_rel_dyn_type((u2)pHeader->e_machine,(u4)ELF32_R_TYPE(pRelplt[j].r_info),(u1*)buf);
					printf("%-15s ",buf);
					if(pRelaMem[ELF32_R_SYM(pRelplt[j].r_info)].st_name != 0){
						printf("%.8x   ",pRelaMem[ELF32_R_SYM(pRelplt[j].r_info)].st_value);
						printf("%-10s  ",(pLookupStrSection->base + pRelaMem[ELF32_R_SYM(pRelplt[j].r_info)].st_name));
					}
					else{
						printf("%-22s","");
					}
					printf("%.8x",pRelplt[j].r_addend);
					printf("\n");
				}
				memset(pLookupSection,0,GET_SIZE(LookupSection));
				memset(pLookupSection,0,GET_SIZE(pLookupStrSection));
			}
		}
		continue;
	}
 
	Exit:
	if(shStringTableMem)
		free(shStringTableMem);
	if(pLookupSection){
		free(pLookupSection);
		pLookupSection = NULL;
	}
	if(pLookupStrSection){
		free(pLookupStrSection);
		pLookupStrSection = NULL;
	}
	return;
}
 
static void get_rel_dyn_type(u2 machineType,u4 rInfo,u1* type){
	switch(machineType){
	case EM_386:
		switch(rInfo){
		case	R_386_NONE:
			memcpy(type,"R_386_NONE",strlen("R_386_NONE"));
			break;
		case	R_386_32:
			memcpy(type,"R_386_32",strlen("R_386_32"));
			break;
		case	R_386_PC32:
			memcpy(type,"R_386_NONE",strlen("R_386_PC32"));
			break;
		case	R_386_GOT32:
			memcpy(type,"R_386_GOT32",strlen("R_386_GOT32"));
			break;
		case	R_386_PLT32:
			memcpy(type,"R_386_PLT32",strlen("R_386_PLT32"));
			break;
		case	R_386_COPY:
			memcpy(type,"R_386_COPY",strlen("R_386_COPY"));
			break;
		case	R_386_GLOB_DAT:
			memcpy(type,"R_386_GLOB_DAT",strlen("R_386_GLOB_DAT"));
			break;
		case	R_386_JMP_SLOT:
			memcpy(type,"R_386_JMP_SLOT",strlen("R_386_JMP_SLOT"));
			break;
		case	R_386_RELATIVE:
			memcpy(type,"R_386_RELATIVE",strlen("R_386_RELATIVE"));
			break;
		case	R_386_GOTOFF:
			memcpy(type,"R_386_GOTOFF",strlen("R_386_GOTOFF"));
			break;
		case	R_386_GOTPC:
			memcpy(type,"R_386_GLOB_DAT",strlen("R_386_GOTPC"));
			break;
		case	R_386_TLS_TPOFF:
			memcpy(type,"R_386_TLS_TPOFF",strlen("R_386_TLS_TPOFF"));
			break;
		case	R_386_TLS_IE:
			memcpy(type,"R_386_TLS_IE",strlen("R_386_TLS_IE"));
			break;
		case	R_386_TLS_GOTIE:
			memcpy(type,"R_386_TLS_GOTIE",strlen("R_386_TLS_GOTIE"));
			break;
		case	R_386_TLS_LE:
			memcpy(type,"R_386_TLS_LE",strlen("R_386_TLS_LE"));
			break;
		case	R_386_TLS_GD:
			memcpy(type,"R_386_TLS_GD",strlen("R_386_TLS_GD"));
			break;
		case	R_386_TLS_LDM:
			memcpy(type,"R_386_TLS_LDM",strlen("R_386_TLS_LDM"));
			break;
		case	R_386_16:
			memcpy(type,"R_386_16",strlen("R_386_16"));
			break;
		case	R_386_PC16:
			memcpy(type,"R_386_PC16",strlen("R_386_PC16"));
			break;
		case	R_386_8:
			memcpy(type,"R_386_8",strlen("R_386_8"));
			break;
		case	R_386_PC8:
			memcpy(type,"R_386_PC8",strlen("R_386_PC8"));
			break;
		case	R_386_TLS_GD_32:
			memcpy(type,"R_386_TLS_GD_32",strlen("R_386_TLS_GD_32"));
			break;
		case	R_386_TLS_GD_PUSH:
			memcpy(type,"R_386_TLS_GD_PUSH",strlen("R_386_TLS_GD_PUSH"));
			break;
		case	R_386_TLS_GD_CALL:
			memcpy(type,"R_386_TLS_GD_CALL",strlen("R_386_TLS_GD_CALL"));
			break;
		case	R_386_TLS_GD_POP:
			memcpy(type,"R_386_TLS_GD_POP",strlen("R_386_TLS_GD_POP"));
			break;
		case	R_386_TLS_LDM_32:
			memcpy(type,"R_386_TLS_LDM_32",strlen("R_386_TLS_LDM_32"));
			break;
		case	R_386_TLS_LDM_PUSH:
			memcpy(type,"R_386_TLS_LDM_PUSH",strlen("R_386_TLS_LDM_PUSH"));
			break;
		case	R_386_TLS_LDM_CALL:
			memcpy(type,"R_386_TLS_LDM_CALL",strlen("R_386_TLS_LDM_CALL"));
			break;
		case	R_386_TLS_LDM_POP:
			memcpy(type,"R_386_TLS_LDM_POP",strlen("R_386_TLS_LDM_POP"));
			break;
		case	R_386_TLS_LDO_32:
			memcpy(type,"R_386_TLS_LDO_32",strlen("R_386_TLS_LDO_32"));
			break;
		case	R_386_TLS_IE_32:
			memcpy(type,"R_386_TLS_IE_32",strlen("R_386_TLS_IE_32"));
			break;
		case	R_386_TLS_LE_32:
			memcpy(type,"R_386_TLS_LE_32",strlen("R_386_TLS_LE_32"));
			break;
		case	R_386_TLS_DTPMOD32:
			memcpy(type,"R_386_TLS_DTPMOD32",strlen("R_386_TLS_DTPMOD32"));
			break;
		case	R_386_TLS_DTPOFF32:
			memcpy(type,"R_386_TLS_DTPOFF32",strlen("R_386_TLS_DTPOFF32"));
			break;
		case	R_386_TLS_TPOFF32:
			memcpy(type,"R_386_TLS_TPOFF32",strlen("R_386_TLS_TPOFF32"));
			break;
		case	R_386_IRELATIVE:
			memcpy(type,"R_386_IRELATIVE",strlen("R_386_IRELATIVE"));
			break;
		default:
			break;
		}
		break;
	case EM_ARM:
		switch(rInfo){
		case	R_ARM_NONE:
			memcpy(type,"R_ARM_NONE",strlen("R_ARM_NONE"));
			break;
		case	R_ARM_PC24:
			memcpy(type,"R_ARM_PC24",strlen("R_ARM_PC24"));
			break;
		case	R_ARM_ABS32:
			memcpy(type,"R_ARM_ABS32",strlen("R_ARM_ABS32"));
			break;
		case	R_ARM_REL32:
			memcpy(type,"R_ARM_REL32",strlen("R_ARM_REL32"));
			break;
		case	R_ARM_PC13:
			memcpy(type,"R_ARM_PC13",strlen("R_ARM_PC13"));
			break;
		case	R_ARM_ABS16:
			memcpy(type,"R_ARM_ABS16",strlen("R_ARM_ABS16"));
			break;
		case	R_ARM_ABS12:
			memcpy(type,"R_ARM_ABS12",strlen("R_ARM_ABS12"));
			break;
		case	R_ARM_THM_ABS5:
			memcpy(type,"R_ARM_THM_ABS5",strlen("R_ARM_THM_ABS5"));
			break;
		case	R_ARM_ABS8:
			memcpy(type,"R_ARM_ABS8",strlen("R_ARM_ABS8"));
			break;
		case	R_ARM_SBREL32:
			memcpy(type,"R_ARM_SBREL32",strlen("R_ARM_SBREL32"));
			break;
		case	R_ARM_THM_PC22:
			memcpy(type,"R_ARM_THM_PC22",strlen("R_ARM_THM_PC22"));
			break;
		case	R_ARM_THM_PC8:
			memcpy(type,"R_ARM_THM_PC8",strlen("R_ARM_THM_PC8"));
			break;
		case	R_ARM_AMP_VCALL9:
			memcpy(type,"R_ARM_AMP_VCALL9",strlen("R_ARM_AMP_VCALL9"));
			break;
		case	R_ARM_SWI24:
			memcpy(type,"R_ARM_SWI24",strlen("R_ARM_SWI24"));
			break;
		case	R_ARM_THM_SWI8:
			memcpy(type,"R_ARM_THM_SWI8",strlen("R_ARM_THM_SWI8"));
			break;
		case	R_ARM_XPC25:
			memcpy(type,"R_ARM_XPC25",strlen("R_ARM_XPC25"));
			break;
		case	R_ARM_THM_XPC22:
			memcpy(type,"R_ARM_THM_XPC22",strlen("R_ARM_THM_XPC22"));
			break;
		case	R_ARM_TLS_DTPMOD32:
			memcpy(type,"R_ARM_TLS_DTPMOD32",strlen("R_ARM_TLS_DTPMOD32"));
			break;
		case	R_ARM_TLS_DTPOFF32:
			memcpy(type,"R_ARM_TLS_DTPOFF32",strlen("R_ARM_TLS_DTPOFF32"));
			break;
		case	R_ARM_TLS_TPOFF32:
			memcpy(type,"R_ARM_TLS_TPOFF32",strlen("R_ARM_TLS_TPOFF32"));
			break;
		case	R_ARM_COPY:
			memcpy(type,"R_ARM_COPY",strlen("R_ARM_COPY"));
			break;
		case	R_ARM_GLOB_DAT:
			memcpy(type,"R_ARM_GLOB_DAT",strlen("R_ARM_GLOB_DAT"));
			break;
		case	R_ARM_JUMP_SLOT:
			memcpy(type,"R_ARM_JUMP_SLOT",strlen("R_ARM_JUMP_SLOT"));
			break;
		case	R_ARM_RELATIVE:
			memcpy(type,"R_ARM_RELATIVE",strlen("R_ARM_RELATIVE"));
			break;
		case	R_ARM_GOTOFF:
			memcpy(type,"R_ARM_GOTOFF",strlen("R_ARM_GOTOFF"));
			break;
		case	R_ARM_GOTPC:
			memcpy(type,"R_ARM_GOTPC",strlen("R_ARM_GOTPC"));
			break;
		case	R_ARM_GOT32:
			memcpy(type,"R_ARM_GOT32",strlen("R_ARM_GOT32"));
			break;
		case	R_ARM_PLT32:
			memcpy(type,"R_ARM_PLT32",strlen("R_ARM_PLT32"));
			break;
		case	R_ARM_GNU_VTENTRY:
			memcpy(type,"R_ARM_GNU_VTENTRY",strlen("R_ARM_GNU_VTENTRY"));
			break;
		case	R_ARM_GNU_VTINHERIT:
			memcpy(type,"R_ARM_GNU_VTINHERIT",strlen("R_ARM_GNU_VTINHERIT"));
			break;
		case	R_ARM_RSBREL32:
			memcpy(type,"R_ARM_RSBREL32",strlen("R_ARM_RSBREL32"));
			break;
		case	R_ARM_THM_RPC22:
			memcpy(type,"R_ARM_THM_RPC22",strlen("R_ARM_THM_RPC22"));
			break;
		case	R_ARM_RREL32:
			memcpy(type,"R_ARM_RREL32",strlen("R_ARM_RREL32"));
			break;
		case	R_ARM_RABS32:
			memcpy(type,"R_ARM_RABS32",strlen("R_ARM_RABS32"));
			break;
		case	R_ARM_RPC24:
			memcpy(type,"R_ARM_RPC24",strlen("R_ARM_RPC24"));
			break;
		case	R_ARM_RBASE:
			memcpy(type,"R_ARM_RBASE",strlen("R_ARM_RBASE"));
			break;
		default:
			break;
		}
		break;
	default :
		//TODO other  ellipsis...
		break;
	}
}


练习：读取section names
从这一讲开始，都会有练习，方便我们把前面的理论知识综合运用。

下面这个练习的目标是：从一个ELF文件中读取存储section name的字符串表。前面讲过，该字符串表也是一个section，section header table中有其对应的section header，并且ELF文件头中给出了节名字符串表对应的section header的索引，e_shstrndx。

我们的思路是这样：

从ELF header中读取section header table的起始位置，每个section header的大小，以及节名字符串表对应section header的索引。

计算section_header_table_offset + section_header_size * e_shstrndx 就是节名字符串表对应section header的偏移。

读取section header，可以从中得到节名字符串表在文件中的偏移和大小。

把节名字符串表读取到内存中，打印其内容。

代码如下：



/* 64位ELF文件读取section name string table */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char *argv[])
{
    /* 打开本地的ELF可执行文件hello */
    FILE *fp = fopen("./hello", "rb");
    if(!fp) {
        perror("open ELF file");
        exit(1);
    }

    /* 1. 通过读取ELF header得到section header table的偏移 */
    /* for 64 bit ELF,
       e_ident(16) + e_type(2) + e_machine(2) +
       e_version(4) + e_entry(8) + e_phoff(8) = 40 */
    fseek(fp, 40, SEEK_SET);
    uint64_t sh_off;
    int r = fread(&sh_off, 1, 8, fp);
    if (r != 8) {
        perror("read section header offset");
        exit(2);
    }
    /* 得到的这个偏移值，可以用`reaelf -h hello`来验证是否正确 */
    printf("section header offset in file: %ld (0x%lx)\n", sh_off, sh_off);

    /* 2. 读取每个section header的大小e_shentsize,
       section header的数量e_shnum,
       以及对应section name字符串表的section header的索引e_shstrndx
       得到这些值后，都可以用`readelf -h hello`来验证是否正确 */
    /* e_flags(4) + e_ehsize(2) + e_phentsize(2) + e_phnum(2) = 10 */
    fseek(fp, 10, SEEK_CUR);
    uint16_t sh_ent_size;            /* 每个section header的大小 */
    r = fread(&sh_ent_size, 1, 2, fp);
    if (r != 2) {
        perror("read section header entry size");
        exit(2);
    }
    printf("section header entry size: %d\n", sh_ent_size);

    uint16_t sh_num;            /* section header的数量 */
    r = fread(&sh_num, 1, 2, fp);
    if (r != 2) {
        perror("read section header number");
        exit(2);
    }
    printf("section header number: %d\n", sh_num);

    uint16_t sh_strtab_index;   /* 节名字符串表对应的节头的索引 */
    r = fread(&sh_strtab_index, 1, 2, fp);
    if (r != 2) {
        perror("read section header string table index");
        exit(2);
    }
    printf("section header string table index: %d\n", sh_strtab_index);

    /* 3. read section name string table offset, size */
    /* 先找到节头字符串表对应的section header的偏移位置 */
    fseek(fp, sh_off + sh_strtab_index * sh_ent_size, SEEK_SET);
    /* 再从section header中找到节头字符串表的偏移 */
    /* sh_name(4) + sh_type(4) + sh_flags(8) + sh_addr(8) = 24 */
    fseek(fp, 24, SEEK_CUR);
    uint64_t str_table_off;
    r = fread(&str_table_off, 1, 8, fp);
    if (r != 8) {
        perror("read section name string table offset");
        exit(2);
    }
    printf("section name string table offset: %ld\n", str_table_off);

    /* 从section header中找到节头字符串表的大小 */
    uint64_t str_table_size;
    r = fread(&str_table_size, 1, 8, fp);
    if (r != 8) {
        perror("read section name string table size");
        exit(2);
    }
    printf("section name string table size: %ld\n", str_table_size);

    /* 动态分配内存，把节头字符串表读到内存中 */
    char *buf = (char *)malloc(str_table_size);
    if(!buf) {
        perror("allocate memory for section name string table");
        exit(3);
    }
    fseek(fp, str_table_off, SEEK_SET);
    r = fread(buf, 1, str_table_size, fp);
    if(r != str_table_size) {
        perror("read section name string table");
        free(buf);
        exit(2);
    }
    uint16_t i;
    for(i = 0; i < str_table_size; ++i) {
        /* 如果节头字符串表中的字节是0，就打印`\0` */
        if (buf[i] == 0)
            printf("\\0");
        else
            printf("%c", buf[i]);
    }
    printf("\n");
    free(buf);
    fclose(fp);
    return 0;
}

#endif